package com.example.vsftpd;

import com.example.vsftpd.util.RunProcessUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * 添加、删除用户
 * @author yangjl
 */
@Controller
@RequestMapping("/user")
public class UserManagementController {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @RequestMapping({"/add", "del"})
    public String add(HttpServletRequest request){
        String seCode = UUID.randomUUID().toString();
        request.setAttribute("seCode4user", seCode);
        request.getSession().setAttribute("seCode4user", seCode);
        return "createUser";
    }

    /**
     *
     * @param uname 操作人员用户名
     * @param pwd  操作人员的密码
     * @param newUserName 待新建的用户的用户名
     * @param dept  待新建用户的所属部门
     * @param seCode
     * @param request
     * @return
     */
    @RequestMapping("/doCreate")
    @ResponseBody
    public String doCreate(String uname, String pwd, String newUserName,
                           String dept, String seCode, HttpServletRequest request){
        Assert.hasText(seCode, "非法访问。");
        try {
            String seCode1 = (String)request.getSession().getAttribute("seCode4user");
            if(seCode.equals(seCode1)){
                doCreate(uname, pwd, newUserName, dept);
                request.getSession().setAttribute("seCode4user", null);
                return "0";
            }else {
                request.getSession().setAttribute("seCode4user", null);
                return "非法访问。";

            }
        } catch (Exception e) {
            e.printStackTrace();
            return "error: "+e.getMessage();
        }

    }

    private synchronized void doCreate(String uname, String oldPwd, String newUserName, String dept) throws IOException {

        Assert.hasText(uname, "user name must be has value.");
        Assert.hasText(oldPwd, "user pwd must be has value.");
        Assert.hasText(newUserName, "new userName must be has value.");
        Assert.hasText(dept, "new user dept must be has value.");
        /**
         * 分为4步：
         * 1、	建立用户存储用的个人根文件夹；
         * 2、	创建用户名和默认密码；让新用户配置生效；
         * 3、	建立用户权限分配规则文件；
         * 4、	分配共享目录权限。
         */
        // 首先验证操作员的用户名和密码是否正确
        final String userInfoFilePath = "/etc/vsftpd/virtusers";
        File pwdFile = new File(userInfoFilePath);
        List<String> lines;
        if(pwdFile.exists()){
            boolean isLoginSuccess = false;
            lines = FileUtils.readLines(pwdFile, "utf-8");
            for(int i=0;i<lines.size();i++){
                String unameLine = lines.get(i);
                if(unameLine.equalsIgnoreCase(uname)){
                    String pwd = lines.get(i+1);//当前密码
                    if(oldPwd.equals(pwd)){
                        isLoginSuccess = true;
                    }
                    break;
                }
            }
            if(!isLoginSuccess){
                String msg = "创建失败：操作员用户名或密码不正确！";
                logger.error("{}", msg);
                throw new RuntimeException(msg);
            }
        }else {
            String msg = "创建失败：用户属性文件丢失！";
            logger.error(" {}", msg);
            throw new RuntimeException(msg);
        }
        // 检查待添加的用户是否已经存在
        for(String unameLine: lines){
            if(unameLine.equalsIgnoreCase(newUserName)){
                throw new RuntimeException("已存在用户 "+newUserName+" 。");
            }
        }
        logger.info("操作员：{}，准备添加新用户：{}", uname, newUserName);

        // step 1: 建立用户存储用的个人根文件夹；
        final String ftpDirRoot = "/data/ftp/";
        File newUserDir = new File(ftpDirRoot + dept + "/" + newUserName + "/corp_share/" );
        if(!newUserDir.exists()){
            newUserDir.mkdirs();
        }else {
//            throw new RuntimeException("new userName [ " + newUserName + " ] already exist.");
        }

        String[] cmd = { "sh", "-c", "chown -R ftpuser:ftpuser "+ newUserDir.getParent() };
        RunProcessUtils.execSimpleCmd(ftpDirRoot, cmd);

        // step 2: 创建用户名和默认密码；让新用户配置生效；
        lines.add(newUserName);
        lines.add(newUserName+"1234");//默认密码。用户以后可以自己修改。
        FileUtils.writeLines(pwdFile, lines);

        String[] cmds2 = { "sh", "-c", "db_load -T -t hash -f /etc/vsftpd/virtusers /etc/vsftpd/virtusers.db" };
        RunProcessUtils.execSimpleCmd("./", cmds2);

        // step 3: 建立用户权限分配规则文件；
        File newUserConfigFile = new File("/etc/vsftpd/vconf/" + newUserName);
        if(!newUserConfigFile.exists()){
            newUserConfigFile.createNewFile();//新建权限文件
            String s = "local_root=/data/ftp/{0}/{1}/\n" +
                    "write_enable=YES\n" +
                    "anon_world_readable_only=NO\n" +
                    "anon_upload_enable=YES\n" +
                    "anon_mkdir_write_enable=YES\n" +
                    "anon_other_write_enable=YES";
            s = MessageFormat.format(s, dept, newUserName);
            FileUtils.write(newUserConfigFile, s, StandardCharsets.UTF_8);

        }else {
            throw new RuntimeException("new UserConfigFile [ /etc/vsftpd/vconf/" + newUserName + " ] already exist.");
        }

        // step 4: 分配共享目录权限。
        String[] cmd3 = { "sh", "-c", "mount -B /data/ftp/corp_share/  /data/ftp/"+dept+"/"+newUserName+"/corp_share" };//链接
        RunProcessUtils.execSimpleCmd(ftpDirRoot, cmd3);
        String[] cmd4 = { "sh", "-c", "mount -o remount,ro /data/ftp/"+dept+"/"+newUserName+"/corp_share" };//设置为只读
        RunProcessUtils.execSimpleCmd(ftpDirRoot, cmd4);
        String[] cmd5 = { "sh", "-c", "mount -o remount,rw /data/" };//更目录重置为可写。
        RunProcessUtils.execSimpleCmd(ftpDirRoot, cmd5);

        // todo  end: 把以上脚本写入 /data/loadFtpCustomDirMap.sh 文件，以便服务器重启后自动添加用户。
        File loadFtpCustomDirMap = new File("/data/loadFtpCustomDirMap.sh");
        List<String> shellLines = FileUtils.readLines(loadFtpCustomDirMap, "utf-8");

        int endCmdLine = shellLines.indexOf("mount -o remount,rw /data/");
        shellLines.add(endCmdLine, "mount -B /data/ftp/corp_share/  /data/ftp/"+dept+"/"+newUserName+"/corp_share");
        shellLines.add(endCmdLine+1, "mount -o remount,ro /data/ftp/"+dept+"/"+newUserName+"/corp_share");

        FileUtils.writeLines(loadFtpCustomDirMap, shellLines);
    }


    @RequestMapping("/doDelete")
    @ResponseBody
    public synchronized String doDelete(String uname, String pwd, String newUserName,
                           String dept, String seCode, HttpServletRequest request){
        Assert.hasText(seCode, "非法访问。");
        try {
            String seCode1 = (String)request.getSession().getAttribute("seCode4user");
            if(seCode.equals(seCode1)){

                Assert.hasText(uname, "user name must be has value.");
                Assert.hasText(pwd, "user pwd must be has value.");
                Assert.hasText(newUserName, "new userName must be has value.");
                Assert.hasText(dept, "new user dept must be has value.");
                /**
                 * 分为4步：
                 * 1、	建立用户存储用的个人根文件夹；
                 * 2、	创建用户名和默认密码；让新用户配置生效；
                 * 3、	建立用户权限分配规则文件；
                 * 4、	分配共享目录权限。
                 */
                // 首先验证操作员的用户名和密码是否正确
                final String userInfoFilePath = "/etc/vsftpd/virtusers";
                File pwdFile = new File(userInfoFilePath);
                List<String> lines;
                if(pwdFile.exists()){
                    boolean isLoginSuccess = false;
                    lines = FileUtils.readLines(pwdFile, "utf-8");
                    for(int i=0;i<lines.size();i++){
                        String unameLine = lines.get(i);
                        if(unameLine.equalsIgnoreCase(uname)){
                            String db_pwd = lines.get(i+1);//当前密码
                            if(pwd.equals(db_pwd)){
                                isLoginSuccess = true;
                            }
                            break;
                        }
                    }
                    if(!isLoginSuccess){
                        String msg = "删除失败：操作员用户名或密码不正确！";
                        logger.error("{}", msg);
                        throw new RuntimeException(msg);
                    }
                }else {
                    String msg = "删除失败：用户属性文件丢失！";
                    logger.error(" {}", msg);
                    throw new RuntimeException(msg);
                }
                // 检查待删除的用户是否存在
                boolean isDelUserExist = false;
                List<String> newlines = new LinkedList<>();
                for(int i=0;i<lines.size(); i++){
                    String unameLine = lines.get(i);
                    if(unameLine.equalsIgnoreCase(newUserName)){
                        isDelUserExist = true;
                        i++;//跳过下一行，密码
                    }else {
                        newlines.add(unameLine);
                    }
                }
                if(isDelUserExist==false){
                    throw new RuntimeException( newUserName + " 用户不存在！");
                }
                logger.info("操作员：{}，正在删除用户：{}", uname, newUserName);

                FileUtils.writeLines(pwdFile, newlines);

                // 需要先删除旧的文件，不然db里还会有被删除的用户，他还能登陆。
                String[] cmds3 = { "sh", "-c", "rm -rf /etc/vsftpd/virtusers.db" };
                RunProcessUtils.execSimpleCmd("./", cmds3);

                String[] cmds2 = { "sh", "-c", "db_load -T -t hash -f /etc/vsftpd/virtusers /etc/vsftpd/virtusers.db" };
                RunProcessUtils.execSimpleCmd("./", cmds2);

                request.getSession().setAttribute("seCode4user", null);
                return "0";
            }else {
                request.getSession().setAttribute("seCode4user", null);
                return "非法访问。";

            }
        } catch (Exception e) {
            e.printStackTrace();
            return "error: "+e.getMessage();
        }

    }

}
